package com.gzhryc.shared_device.iot.core.aliyun;

import com.aliyun.mns.client.CloudAccount;
import com.aliyun.mns.client.CloudQueue;
import com.aliyun.mns.client.MNSClient;
import com.aliyun.mns.model.Message;
import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.exceptions.ClientException;
import com.aliyuncs.exceptions.ServerException;
import com.aliyuncs.iot.model.v20180120.PubRequest;
import com.aliyuncs.iot.model.v20180120.PubResponse;
import com.aliyuncs.iot.model.v20180120.RRpcRequest;
import com.aliyuncs.iot.model.v20180120.RRpcResponse;
import com.aliyuncs.profile.DefaultProfile;
import com.aliyuncs.profile.IClientProfile;
import com.gzhryc.common.json.JsonTools;
import com.gzhryc.common.logging.Logger;
import com.gzhryc.shared_device.iot.core.*;
import com.gzhryc.shared_device.iot.core.aliyun.models.AliyunIOTConfig;
import com.gzhryc.shared_device.iot.core.aliyun.models.AliyunIOTSynResponse;
import com.gzhryc.shared_device.iot.core.enums.EIOTType;

import java.util.Base64;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;

/**
 * 阿里云MQTT版物联网客户端
 * 
 * @author zhanghao
 *
 */
public class AliyunMnsIOTClient implements IOTClient {

	static Logger log = Logger.getLogger(AliyunMnsIOTClient.class);

	final AliyunIOTConfig mConfig;
	final IOTNodeEntity mIOTNode;
	final IOTClientEventListener mListener;

	DefaultAcsClient apiClient;
	AtomicBoolean isRunning;
	MNSClient client;

	Integer poolSize = 2;

	public AliyunMnsIOTClient(AliyunIOTConfig config,IOTNodeEntity iotNode, IOTClientEventListener listener) {
		this.mConfig = config;
		this.mListener = listener;
		this.mIOTNode = iotNode;
		this.isRunning = new AtomicBoolean(false);
		if (config.getPoolSize() == null) {
			this.poolSize = Runtime.getRuntime().availableProcessors();
		} else {
			this.poolSize = config.getPoolSize();
		}
	}

	@Override
	public boolean send(IOTMessage msg) {
		PubRequest request = new PubRequest();
		request.setProductKey(mConfig.getProductKey());
		request.setIotInstanceId(mConfig.getIotInstanceId());
		request.setMessageContent(Base64.getEncoder().encodeToString(msg.getBytes()));
		request.setTopicFullName("/" + mConfig.getProductKey() + msg.getTopic());
		request.setQos(0); // 目前支持QoS0和QoS1
		try {
			PubResponse response = apiClient.getAcsResponse(request);
			if (response.getSuccess()) {
				try {
					mListener.sendMessage(msg, mConfig.getIotId(), request.getTopicFullName());
				} catch (Exception e) {
					log.error(e.getMessage(), e);
				}
				return true;
			} else {
				log.error("{{0}}节点发送失败，返回结果：{{1:json}}", mConfig.getIotId(), response);
			}
		} catch (ServerException e) {
			log.error(e.getMessage(), e);
		} catch (ClientException e) {
			log.error(e.getMessage(), e);
		}
		return false;
	}

	@Override
	public IOTSynResponse synSend(IOTMessage msg, Long times, TimeUnit unit) {
		RRpcRequest request = new RRpcRequest();
		request.setProductKey(mConfig.getProductKey());
		request.setIotInstanceId(mConfig.getIotInstanceId());
		request.setDeviceName(msg.getDeviceSn());
		request.setRequestBase64Byte(Base64.getEncoder().encodeToString(msg.getBytes()));
		request.setTimeout((int) unit.toMillis(times));
		// request.setTopic("/"+mConfig.getProductKey() + msg.getTopic());
		try {
			RRpcResponse response = apiClient.getAcsResponse(request);
			IOTSynResponse result = new AliyunIOTSynResponse(response);
			return result;
		} catch (ServerException e) {
			e.printStackTrace();
		} catch (ClientException e) {
			e.printStackTrace();
		}
		return null;
	}

	@Override
	public void run() {
		try {
			isRunning.set(true);

			IClientProfile profile = DefaultProfile.getProfile(mConfig.getRegionId(), mConfig.getAccessKey(), mConfig.getAccessSecret());
			DefaultProfile.addEndpoint(mConfig.getRegionId(), mConfig.getRegionId(), "Iot", "iot." + mConfig.getRegionId() + ".aliyuncs.com");
			apiClient = new DefaultAcsClient(profile); // 初始化SDK客户端

			final AliyunMnsIOTClient self = this;
			// 启动接收线程
			new Thread() {
				public void run() {
					CloudAccount account = new CloudAccount(mConfig.getAccessKey(), mConfig.getAccessSecret(), mConfig.getAccountEndpoint());
					client = account.getMNSClient();
					for (int i = 0; i < poolSize; i++) {
						log.info("启动第" + (i + 1) + "个接收主行程");
						new Thread() {
							public void run() {
								// 获取消息
								CloudQueue queue = client.getQueueRef(mConfig.getQueueName()); // 请输入IoT自动创建的队列名称
								while (isRunning.get()) {
									try {
										Message popMsg = queue.popMessage(7);
										if (popMsg != null) {
											// 启用工作线程
											IOTWorkThreadFactory.get().execute(new MessageWorkThread(self, popMsg));
											queue.deleteMessage(popMsg.getReceiptHandle()); // 从队列中删除消息
										}
									} catch (Exception e) {
										e.printStackTrace();
									}
								}
								log.debug("主线程断开，队列：" + mConfig.getQueueName());
								isRunning.set(false);
							}
						}.start();
					}
				}
			}.start();
		} catch (ClientException e) {
			e.printStackTrace();
		}
	}

	/**
	 * 阿里云返回的对象
	 */
	public static class MessageBody {

		private String messageid;
		private String messagetype;
		private String topic;
		private String payload;
		private Long timestamp;

		public String getMessageid() {
			return messageid;
		}

		public void setMessageid(String messageid) {
			this.messageid = messageid;
		}

		public String getMessagetype() {
			return messagetype;
		}

		public void setMessagetype(String messagetype) {
			this.messagetype = messagetype;
		}

		public String getTopic() {
			return topic;
		}

		public void setTopic(String topic) {
			this.topic = topic;
		}

		public String getPayload() {
			return payload;
		}

		public void setPayload(String payload) {
			this.payload = payload;
		}

		public Long getTimestamp() {
			return timestamp;
		}

		public void setTimestamp(Long timestamp) {
			this.timestamp = timestamp;
		}
	}

	public class MessageWorkThread implements Runnable {

		private final AliyunMnsIOTClient iotClient;
		private final Message msg;

		public MessageWorkThread(AliyunMnsIOTClient iotClient, Message msg) {
			this.iotClient = iotClient;
			this.msg = msg;
		}

		@Override
		public void run() {
			String json = msg.getMessageBodyAsString();
			MessageBody msgBody = JsonTools.fromJson(json, MessageBody.class);
			if (msgBody.getMessagetype().equals("status")) {
				AliyunIOTClientEvent event = new AliyunIOTClientEvent(iotClient, msgBody.topic, msgBody.payload);
				mListener.stateChange(event);
			} else {
				AliyunIOTClientEvent event = new AliyunIOTClientEvent(iotClient, msgBody.topic, msgBody.payload);
				mListener.receiveMessage(event);
			}
		}
	}

	@Override
	public void close() {

	}

	@Override
	public EIOTType getIOTType() {
		return EIOTType.ALIYUN;
	}

	@Override
	public IOTNodeEntity getIOTNote() {
		return mIOTNode;
	}

}
